#!/usr/bin/env python

'''
Created on Feb 9, 2011

@author: ziegeldorf
'''

import TikZ
import PerformanceSet
import re
import sys
import math
from itertools import izip
import numpy as np

def usage():
    print "usage: Analyzer.py <results dir> <equations file> [options]"
    print "options:"
    print " -d --detailed:   print detailed evaluation output"
    print " -c --comments:   parse comments from performance header and print them with sensor information"
    

class Equation:
    def __init__(self, equation):
        self.eq = equation.strip()
        if self.eq.find("=:") != -1:
            self.type = "DEFINITION"
            parts = self.eq.split("=:")
        else:
            parts = self.eq.split("=")
            if (len(parts) == 2) and parts[1] != "":
                self.type = "COMPARE"
            else:
                self.type = "EVALUATE"
        self.lefteq = parts[0].strip()
        self.righteq = parts[1].strip()
        print "Got equation of type %s" % (self.type)

    def eval(self, values, comments):
        try:
            y = compile(self.lefteq, "", "eval")
            left_val  = eval(y, values)
            if self.type == "COMPARE":
                y = compile(self.righteq, "", "eval")
                right_val = eval(y, values)
            elif self.type == "DEFINITION":
                values[self.righteq] = left_val
                right_val = left_val
                comments[self.righteq] = "// " + self.lefteq
            else:
                right_val = -1
            return [left_val, right_val, 0]
        except Exception as e:
            print "Equation could not be evaluated."
            return [0,0, e]
       
    def printEvaluation(self, values, devs, variances, comments=0, detailed=1, tikz=0, table=0):
        lvals = []
        ldevs = []
        [l, r, e] = self.eval(values, comments)
        tcode=""
        tab_delta = ""
        print " -------------------------------------------------------------------------------------"
        print "  Equation: \"%s\"" % self.eq
        print ""
        if l == 0 and r == 0:
            print "  Eval:  invalid equation: " + str(e)
            return
        if self.type == "EVALUATE":
            print "  Eval:      %s =  %0.5f" % ("Result".ljust(50), l)
            r = l
        elif self.type == "DEFINITION":
            print "  Def:       %s =  %0.5f" % (self.righteq.ljust(50), values[self.righteq])
            print "                =  %s" % (self.lefteq)
        else:
            if r == 0:
                r = 0.00001
            print "  Eval:      %s =  %0.5f    %6.2f %%" % ("Left side".ljust(50), l, (l)/1.0/r*100)
            print "             %50s +  %0.5f    %6.2f %%" % ("delta".ljust(50), r-l, (r-l)/r*100)
            tab_delta = "\t\hspace{1.5cm}%s & %0.2f \\hspace{0.99cm} & %0.2f \\\\ \\hline\n" % ("\\emph{Processing}", (r-l)*1000, (r-l)/r*100)
            print "             %s------------------------- " % (" ".ljust(50)) 
            print "             %s =  %0.5f" % ("Rigth side".ljust(50), r)

        
        if detailed and not self.type == "DEFINITION":
            tab_top = "\\begin{table}\n" \
                      "  \\small\n" \
                      "  \\centering\n" \
                      "  \\begin{tabular}{|p{8cm}|r|r|} \\hline \n" \
                      "  \\textbf{Process} & \\textbf{Time (ms)} & \\textbf{Percentage (\\%)} \\\\ \\hline \\hline \n"
            tab_left = ""
            tab_right = ""
            print ""
            print "  Detailed (left side):"
            v = re.findall(r'\w+', self.lefteq)
            for var in v:
                if var in values:
                    try: 
                        print "             %s &  %6.2f (%6.2f)   & %6.2f \\%% \\\\ \\hline" % (var.ljust(50), values[var]*1000, devs[var]*1000, values[var] / 1.0 / r * 100)
                        tab_left += "\t\\hspace{1.5cm}%s &  %0.2f (%0.2f)   & %0.2f \\\\\n" % (var.replace("_", "-"), values[var]*1000, devs[var]*1000, values[var] / 1.0 / r * 100)
                    except:
                        print "             %s &  %6.2f (%6.2f)   & %6.2f \\%% \\\\ \\hline" % (var.ljust(50), values[var]*1000, 0.0, values[var] / 1.0 / r * 100)
                        tab_left += "\t\\hspace{1.5cm}%s &  %0.2f (%0.2f) & %0.2f \\\\ \n" % (var.replace("_", "-"), values[var]*1000, 0.0, values[var] / 1.0 / r * 100)
                    lvals.append(values[var]*1000)
                    try:
                        ldevs.append(devs[var]*1000)
                    except:
                        ldevs.append(0.0)

            print "  Detailed (right side):"
            v = re.findall(r'\w+', self.righteq)
            for var in v:
                if var in values:
                    try: 
                        print "             %s &  %6.2f (%6.2f)   & %6.2f %%    %s" % (var.ljust(50), values[var]*1000, devs[var]*1000, values[var] / 1.0 / r * 100, comments[var])
                        tab_right = "\t\\textbf{%s} &  \\textbf{%0.2f (%0.2f)} & \\textbf{%0.2f} \\\\ \\hline \n" % (var.replace("_", "-"), values[var]*1000, devs[var]*1000, values[var] / 1.0 / r * 100)
                    except:
                        tab_right = "\t\\textbf{%s} &  \\textbf{%0.2f (%0.2f)} & \\textbf{%0.2f} \\\\ \\hline \n" % (var.replace("_", "-"), values[var]*1000, 0.0, values[var] / 1.0 / r * 100)
                        
            if tikz and self.type == "COMPARE":
                print lvals
                print ldevs
                print "------------- Begin Tikz picture -----------------"
                try:
                    pic = TikZ.TikzPicture(lvals, ldevs, r*1000, devs[self.righteq]*1000)
                except:
                    pic = TikZ.TikzPicture(lvals, ldevs, r*1000, 0.0)
                pic.draw()
                print "-------------  End Tikz picture  -----------------"

            if table:
                tab_bottom = "  \\end{tabular}\n" \
                             "  \\caption{some table...}\n" \
                             "  \\label{some label...}\n" \
                             "\\end{table}\n"
                print tab_top + tab_right + tab_left + tab_delta + tab_bottom

        print " -------------------------------------------------------------------------------------"

class Analyzer:
    def __init__(self, results, equations_file):
        self.perf_set = PerformanceSet.PerformanceSet(results)
        self.read_equations(equations_file)
        self.values = self.perf_set.averageList()
        self.dev = self.perf_set.devList()
        self.variances = self.perf_set.varList()
        for key in sorted(self.values):
            if not key in self.perf_set.sensors.comments:
                self.perf_set.sensors.comments[key] = ""
            #print " %s  ->  %0.5f" % (key.ljust(35), self.values[key])
        
    def read_equations(self, equations_file):
        self.equations = []
        for line in open(equations_file):
            if not line.startswith("#") and not line.strip() == "":
                eq = Equation(line)
                self.equations.append(eq)
    
    def printEvaluations(self):
        for eq in self.equations:
            eq.printEvaluation(self.values, self.dev, self.variances, self.perf_set.sensors.comments)
            
    def stdDev(self, *args):
        sums = []
        for line in izip(*[self.perf_set.measurements[sensor]['0'] for sensor in args]):
            line = map(float, line)
            sums.append(sum(line))
        sums = np.array(sums)
        print sums
        print "%f" % (sums.std())

    def stdDev2(self):
        sums = []
        sensors = ["PERF_NEW_CONN", "PERF_MBOX_I1_M1", "PERF_MBOX_R1_M1", "PERF_MBOX_I2_M1", "PERF_MBOX_R2_M1"]
        for line in izip(*[self.perf_set.measurements[sensor]['0'] for sensor in sensors]):
            line = map(float, line)
            sums.append(line[0]-sum(line[1:]))
        sums = np.array(sums)
        print "%f" % (sums.std())

if len(sys.argv) < 3:
    usage()
    sys.exit()

print "Reading equations from file: " + sys.argv[0]
print "Reading measurements from directory: " + sys.argv[1]

a = Analyzer(sys.argv[1], sys.argv[2])
a.printEvaluations()
a.perf_set.printSensors()

a.stdDev("PERF_MBOX_I1_M1", "PERF_MBOX_R1_M1", "PERF_MBOX_I2_M1", "PERF_MBOX_R2_M1")
a.stdDev2()
